package svc.elib.socnet;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;

import svc.elib.db.Author;
import svc.elib.db.Database;

/**
 * Algorithm for tracking component evolution
 * @author svc
 */
public class TrackComponentEvolution {
	
	private Net[] snapshots;
	private int startYear;
	
	private static final int STABILE_COMPONENT = 1;
	private static final int EXTENDED_COMPONENT = 2;
	private static final int MERGED_COMPONENT = 3;
	private static final int NEW_COMPONENT = 4;
	
	public TrackComponentEvolution(Net net) {
		EvolutionarySnapshots es = new EvolutionarySnapshots(net);
		snapshots = es.getSnapshots();
		startYear = es.getStartYear();
	}
	
	public void determineEvents(boolean excludeTrivialComponents) {
		
		System.out.println("year, numNew, numStabile, numExtended, numMerged");
		
		for (int i = 0; i < snapshots.length - 1; i++) {
			Net prev = snapshots[i];
			Net next = snapshots[i + 1];
			
			if (excludeTrivialComponents) {
				TrivialComponents tc = new TrivialComponents(prev);
				tc.determine();
				tc.filter();
			}
			
			ConnectedComponents cs = new ConnectedComponents(prev);
			cs.resolveComponents();
			LinkedList<Net> prevComponents = cs.getComponents();
			
			if (excludeTrivialComponents) {
				TrivialComponents tc = new TrivialComponents(next);
				tc.determine();
				tc.filter();
			}
			
			cs = new ConnectedComponents(next);
			cs.resolveComponents();
			LinkedList<Net> nextComponents = cs.getComponents();
			
			int numExtended = 0, numNew = 0, numStabile = 0, numMerged = 0;
			
			// determine type of component for each component in the next snapshot
			for (int j = 0; j < nextComponents.size(); j++) {
				Net comp = nextComponents.get(j);
				int evolutionaryEvent = determineType(comp, prevComponents);
				switch (evolutionaryEvent) {
				case EXTENDED_COMPONENT: numExtended++; break;
				case NEW_COMPONENT: numNew++; break;
				case STABILE_COMPONENT: numStabile++; break;
				case MERGED_COMPONENT: numMerged++; break;
				}
			}
			
			System.out.println((startYear + i) + ", " + numNew + ", " + numStabile + ", " + numExtended + ", " + numMerged);
		}
	}

	private int determineType(Net comp, LinkedList<Net> prevComponents) {
		int[] m = new int[prevComponents.size()];
		
		for (int i = 0; i < prevComponents.size(); i++) {
			Net c = prevComponents.get(i);
			int matchCount = match(comp, prevComponents.get(i));
			if (comp.getNumAuthors() == c.getNumAuthors() && matchCount == c.getNumAuthors()) {
				return STABILE_COMPONENT;
			} else {
				m[i] = matchCount;
			}
		}
		
		int zeroDiffs = 0;
		for (int i = 0; i < m.length; i++) {
			if (m[i] > 0)
				zeroDiffs++;
		}
		
		if (zeroDiffs == 0)
			return NEW_COMPONENT;
		else
		if (zeroDiffs == 1)
			return EXTENDED_COMPONENT;
		else
			return MERGED_COMPONENT;
	}
	
	private int match(Net n1, Net n2) {
		Iterator<Author> it = n1.getGraph().getVertices().iterator();
		
		int matchCount = 0;
		while (it.hasNext()) {
			Author a = it.next();
			if (n2.getGraph().containsVertex(a)) {
				matchCount++;
			}
		}
		
		return matchCount;
	}
	
	
	public static void main(String[] args) 
		throws IOException
	{
		Database db = new Database("eLibData.csv", 1932, 2011);
		System.out.println(db.info());
		SocConstructor soc = new SocConstructor(db);
		Net net = soc.getNet();
		TrackComponentEvolution tc = null;
		
		/*
		tc = new TrackComponentEvolution(net);
		System.out.println("Trivial components excluded .... ");
		tc.determineEvents(true);
		
		tc = new TrackComponentEvolution(net);
		System.out.println("All components .... ");
		tc.determineEvents(false);
		*/
		
		ConnectedComponents cs = new ConnectedComponents(net);
		cs.resolveComponents();
		Net largestComponent = cs.getComponents().get(0);
		tc = new TrackComponentEvolution(largestComponent);
		System.out.println("Largest connected component... ");
		tc.determineEvents(false);
	}
}
